﻿/*
** Xin YUAN, 2024, BSD (2)
*/

////////////////////////////////////////////////////////////////////////////////
#ifndef __CTL_CALENDAR_H__
#define __CTL_CALENDAR_H__
////////////////////////////////////////////////////////////////////////////////

#ifndef __CTL_DEF_H__
	#error calendar.h requires def.h to be included first.
#endif

////////////////////////////////////////////////////////////////////////////////
namespace CTL {
////////////////////////////////////////////////////////////////////////////////

//SolarTimeHelper
//  Julian & Gregorian

class SolarTimeHelper
{
public:
	static bool IsLeapYear(int32_t iYear) noexcept
	{
		if ( iYear > 1582 )
			return (iYear % 4) == 0 && ((iYear % 100) != 0 || (iYear % 400) == 0);
		return (iYear % 4) == 0;
	}

	static bool IsDeletedDay(int32_t iYear, int32_t iMonth, int32_t iDay) noexcept
	{
		return iYear == 1582 && iMonth == 10 && (iDay > 4 && iDay < 15);
	}

	static int32_t CalcMonthDays(int32_t iMonth, bool bLeap) noexcept
	{
		assert( iMonth >= 1 && iMonth <= 12 );
		constexpr const uint32_t c_month_days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
		if ( iMonth == 2 && bLeap )
			return 29;
		return c_month_days[iMonth - 1];
	}
	static int32_t CalcMonthDays(int32_t iYear, int32_t iMonth) noexcept
	{
		return CalcMonthDays(iMonth, IsLeapYear(iYear));
	}

	//0 -- sunday, ...
	static int32_t CalcWeekDay(int32_t iYear, int32_t iMonth, int32_t iDay) noexcept
	{
		if ( iMonth == 1 || iMonth == 2 ) {
			-- iYear;
			iMonth += 12;
		}
		int32_t c = iYear / 100;
		int32_t y = iYear - 100 * c;
		int32_t w = y + y / 4 + (13 * (iMonth + 1) / 5) + iDay - 1;
		if ( iYear < 1582 || (iYear == 1582 && (iMonth < 10 || (iMonth == 10 && iDay <= 4))) )
			w = w + 5 - c;
		else
			w = w + c / 4 - 2 * c;
		return (w % 7 + 7) % 7;
	}
	//0-365
	static int32_t CalcDayOrdinal(int32_t iMonth, int32_t iDay, bool bLeap) noexcept
	{
		if ( iMonth < 2 )
			return iDay - 1;
		int32_t count = 0;
		for ( int32_t i = 1; i < iMonth; i ++ )
			count += CalcMonthDays(i, bLeap);
		count += (iDay - 1);
		if ( iYear == 1582 && (iMonth > 10 || (iMonth == 10 && iDay >= 15)) )
			count -= 10;  //deleted days
		return count;
	}
	static int32_t CalcDayOrdinal(int32_t iYear, int32_t iMonth, int32_t iDay) noexcept
	{
		return CalcDayOrdinal(iMonth, iDay, IsLeapYear(iYear));
	}

	static int32_t CalcYearDelta(int32_t iYearS, int32_t iYearE) noexcept
	{
		return iYearE - iYearS;
	}
	static int32_t CalcMonthDelta(int32_t iYearS, int32_t iMonthS,
					int32_t iYearE, int32_t iMonthE) noexcept
	{
		return CalcYearDelta(iYearS, iYearE) * 12 + iMonthE - iMonthS;
	}

	//year-1-1 to 1-1-1
	static int32_t CalcDaysOfAbsYear(int32_t iYear) noexcept
	{
		int32_t y = iYear - 1;
		int32_t d = y * 365 + y / 4 - y / 100 + y / 400;
		if ( iYear > 1582 ) {
			y = 1582;
			d -= 10;  //deleted days
		}
		return d + y / 100 - y / 400;
	}

	static int32_t CalcDayDelta(int32_t iYearS, int32_t iMonthS, int32_t iDayS,
					int32_t iYearE, int32_t iMonthE, int32_t iDayE) noexcept
	{
		int32_t s = CalcDaysOfAbsYear(iYearS);
		s += CalcDayOrdinal(iYearS, iMonthS, iDayS);
		int32_t e = CalcDaysOfAbsYear(iYearE);
		e += CalcDayOrdinal(iYearE, iMonthE, iDayE);
		return e - s;
	}
};

//SolarTime

class SolarTime
{
public:
	SolarTime() noexcept
	{
	}
	SolarTime(int32_t iYear, int32_t iMonth, int32_t iDay,
		int32_t iHour, int32_t iMinute, int32_t iSecond) noexcept
			: m_iYear(iYear), m_iMonth(iMonth), m_iDay(iDay),
			m_iHour(iHour), m_iMinute(iMinute), m_iSecond(iSecond)
	{
	}

	void Set(int32_t iYear, int32_t iMonth, int32_t iDay,
		int32_t iHour, int32_t iMinute, int32_t iSecond) noexcept
	{
		m_iYear = iYear;
		m_iMonth = iMonth;
		m_iDay = iDay;
		m_iHour = iHour;
		m_iMinute = iMinute;
		m_iSecond = iSecond;
	}

	const int32_t& Year() const noexcept
	{
		return m_iYear;
	}
	int32_t& Year() noexcept
	{
		return m_iYear;
	}
	const int32_t& Month() const noexcept
	{
		return m_iMonth;
	}
	int32_t& Month() noexcept
	{
		return m_iMonth;
	}
	const int32_t& Day() const noexcept
	{
		return m_iDay;
	}
	int32_t& Day() noexcept
	{
		return m_iDay;
	}
	const int32_t& Hour() const noexcept
	{
		return m_iHour;
	}
	int32_t& Hour() noexcept
	{
		return m_iHour;
	}
	const int32_t& Minute() const noexcept
	{
		return m_iMinute;
	}
	int32_t& Minute() noexcept
	{
		return m_iMinute;
	}
	const int32_t& Second() const noexcept
	{
		return m_iSecond;
	}
	int32_t& Second() noexcept
	{
		return m_iSecond;
	}

	bool IsValid() const noexcept
	{
		return m_iYear >= 1 && m_iMonth >= 1 && m_iMonth <= 12 && m_iDay >= 1 && m_iDay <= CalcMonthDays(m_iYear, m_iMonth)
			&& m_iHour >= 0 && m_iHour <= 23 && m_iMinute >= 0 && m_iMinute <= 59
			&& m_iSecond >= 0 && m_iSecond <= 60;
	}

private:
	int32_t m_iYear;
	int32_t m_iMonth;
	int32_t m_iDay;
	int32_t m_iHour;
	int32_t m_iMinute;
	int32_t m_iSecond;
};

//LunarTime

class LunarTime
{
public:
	LunarTime() noexcept
	{
	}
	LunarTime(int32_t iYear, int32_t iMonth, int32_t iDay, int32_t iHour) noexcept
			: m_iYear(iYear), m_iMonth(iMonth), m_iDay(iDay), m_iHour(iHour)
	{
	}

	void Set(int32_t iYear, int32_t iMonth, int32_t iDay, int32_t iHour) noexcept
	{
		m_iYear = iYear;
		m_iMonth = iMonth;
		m_iDay = iDay;
		m_iHour = iHour;
	}

	const int32_t& Year() const noexcept
	{
		return m_iYear;
	}
	int32_t& Year() noexcept
	{
		return m_iYear;
	}
	const int32_t& Month() const noexcept
	{
		return m_iMonth;
	}
	int32_t& Month() noexcept
	{
		return m_iMonth;
	}
	const int32_t& Day() const noexcept
	{
		return m_iDay;
	}
	int32_t& Day() noexcept
	{
		return m_iDay;
	}
	const int32_t& Hour() const noexcept
	{
		return m_iHour;
	}
	int32_t& Hour() noexcept
	{
		return m_iHour;
	}

	const int32_t& MonthFlags() const noexcept
	{
		return m_iMonthFlags;
	}
	int32_t& MonthFlags() noexcept
	{
		return m_iMonthFlags;
	}

	bool IsValid() const noexcept
	{
		return m_iYear >= 1 && m_iMonth >= 1 && m_iMonth <= 12 && m_iDay >= 1 && m_iDay <= 30
			&& m_iHour >= 1 && m_iHour <= 12;
	}

	bool IsBig() const noexcept
	{
		return (m_iMonthFlags & 0x01) != 0;
	}
	void SetBig(bool b) noexcept
	{
		if ( b )
			m_iMonthFlags |= 0x00000001;
		else
			m_iMonthFlags &= ~0x00000001;
	}

	bool IsLeap() const noexcept
	{
		return (m_iMonthFlags & 0x02) != 0;
	}
	void SetLeap(bool b) noexcept
	{
		if ( b )
			m_iMonthFlags |= 0x00000002;
		else
			m_iMonthFlags &= ~0x00000002;
	}

private:
	int32_t m_iYear;
	int32_t m_iMonth;
	int32_t m_iMonthFlags;  // 0x01 --- 0(29) 1(30)    0x02 --- leap month
	int32_t m_iDay;
	int32_t m_iHour;
};

//conversion

//1901-1-1 = 1900-11-11(lunar) 4597-11-11(kaiyuan)
//GZ: 7-1 5-1 6-4

class CalendarConversion
{
public:
	constexpr static const int32_t c_base_year = 1901;
	constexpr static const int32_t c_max_year = 2100;
	constexpr static const int32_t c_base_chinese_year = 1900;
	constexpr static const int32_t c_base_chinese_month = 11;
	constexpr static const int32_t c_base_chinese_day = 11;
	constexpr static const int32_t c_base_kaiyuan_year = 4597;

	static void GetChineseMonthInfo(int32_t iChineseYear, int32_t iChineseMonth, bool bLeap,
					int32_t& iDaysInMonth,
					int32_t& iNextMonthYear, int32_t& iNextMonth, bool& bNextLeap) noexcept
	{
		assert( iYear >= c_base_chinese_year && iYear <= c_max_year );
//1900-2100
// | 15 14 13 12 | 11 10  9  8  7  6  5  4  3  2  1  0 |
// | leap month  | days for each month (1 = 29 0 = 30) |
constexpr const uint8_t c_months_year[] = {
0x00,0x04,0xad,0x08,0x5a,0x01,0xd5,0x54,0xb4,0x09,0x64,0x05,0x59,0x45,
0x95,0x0a,0xa6,0x04,0x55,0x24,0xad,0x08,0x5a,0x62,0xda,0x04,0xb4,0x05,
0xb4,0x55,0x52,0x0d,0x94,0x0a,0x4a,0x2a,0x56,0x02,0x6d,0x71,0x6d,0x01,
0xda,0x02,0xd2,0x52,0xa9,0x05,0x49,0x0d,0x2a,0x45,0x2b,0x09,0x56,0x01,
0xb5,0x20,0x6d,0x01,0x59,0x69,0xd4,0x0a,0xa8,0x05,0xa9,0x56,0xa5,0x04,
0x2b,0x09,0x9e,0x38,0xb6,0x08,0xec,0x74,0x6c,0x05,0xd4,0x0a,0xe4,0x6a,
0x52,0x05,0x95,0x0a,0x5a,0x42,0x5b,0x04,0xb6,0x04,0xb4,0x22,0x6a,0x05,
0x52,0x75,0xc9,0x0a,0x52,0x05,0x35,0x55,0x4d,0x0a,0x5a,0x02,0x5d,0x31,
0xb5,0x02,0x6a,0x8a,0x68,0x05,0xa9,0x0a,0x8a,0x6a,0x2a,0x05,0x2d,0x09,
0xaa,0x48,0x5a,0x01,0xb5,0x09,0xb0,0x39,0x64,0x05,0x25,0x75,0x95,0x0a,
0x96,0x04,0x4d,0x54,0xad,0x04,0xda,0x04,0xd4,0x44,0xb4,0x05,0x54,0x85,
0x52,0x0d,0x92,0x0a,0x56,0x6a,0x56,0x02,0x6d,0x02,0x6a,0x41,0xda,0x02,
0xb2,0xa1,0xa9,0x05,0x49,0x0d,0x0a,0x6d,0x2a,0x09,0x56,0x01,0xad,0x50,
0x6d,0x01,0xd9,0x02,0xd1,0x3a,0xa8,0x05,0x29,0x85,0xa5,0x0c,0x2a,0x09,
0x96,0x54,0xb6,0x08,0x6c,0x09,0x64,0x45,0xd4,0x0a,0xa4,0x05,0x51,0x25,
0x95,0x0a,0x2a,0x72,0x5b,0x04,0xb6,0x04,0xac,0x52,0x6a,0x05,0xd2,0x0a,
0xa2,0x4a,0x4a,0x05,0x55,0x94,0x2d,0x0a,0x5a,0x02,0x75,0x61,0xb5,0x02,
0x6a,0x03,0x61,0x45,0xa9,0x0a,0x4a,0x05,0x25,0x25,0x2d,0x09,0x9a,0x68,
0xda,0x08,0xb4,0x09,0xa8,0x59,0x54,0x03,0xa5,0x0a,0x91,0x3a,0x96,0x04,
0xad,0xb0,0xad,0x04,0xda,0x04,0xf4,0x62,0xb4,0x05,0x54,0x0b,0x44,0x5d,
0x52,0x0a,0x95,0x04,0x55,0x22,0x6d,0x02,0x5a,0x71,0xda,0x02,0xaa,0x05,
0xb2,0x55,0x49,0x0b,0x4a,0x0a,0x2d,0x39,0x36,0x01,0x6d,0x80,0x6d,0x01,
0xd9,0x02,0xe9,0x6a,0xa8,0x05,0xa9,0x0a,0x9a,0x4c,0xaa,0x08,0xb6,0x08,
0xb4,0x38,0x6c,0x09,0x54,0x75,0xd4,0x0a,0xa4,0x05,0x45,0x55,0x95,0x0a,
0x9a,0x04,0x55,0x44,0xb5,0x04,0x6a,0x82,0x6a,0x05,0xd2,0x0a,0x92,0x6a,
0x4a,0x05,0x55,0x0a,0x2a,0x4a,0x5a,0x02,0xb5,0x02,0xb2,0x31,0x69,0x03,
0x31,0x73,0xa9,0x0a,0x4a,0x05,0x2d,0x55,0x2d,0x09,0x5a,0x01,0xd5,0x48,
0x74,0x09,0x68,0x89,0x54,0x0b,0xa4,0x0a,0xa9,0x6a,0x95,0x04,0xad,0x08,
0x6a,0x44,0xba,0x04,0x74,0x05,0xb0,0x25,0x54,0x03
};
constexpr const int32_t c_big_leap_month_years[] = {
 6, 14, 19, 25, 33, 36, 38, 41, 44, 52,
55, 79,117,136,147,150,155,158,185,193
};
		//days
		int32_t index = iChineseYear - c_base_chinese_year;
		uint16_t flag = (uint16_t)(c_months_year[2 * index]) | ((uint16_t)(c_months_year[2 * index + 1]) << 8);
		int32_t leap_month = (flag >> 12) & 0x000F;
		iDaysInMonth = (((flag & 0x0FFF) >> (iChineseMonth - 1)) & 0x0001) ? 29 : 30;
		if ( bLeap ) {
			if ( leap_month != iChineseMonth ) {
				iDaysInMonth = 0;
			}
			else {
				iDaysInMonth = 29;
				for ( int32_t i = 0; i < sizeof(c_big_leap_month_years) / sizeof(int32_t); i ++ ) {
					if ( c_big_leap_month_years[i] == index ) {
						iDaysInMonth = 30;
						break;
					}
				}
			}
		}
		//next
		iNextMonthYear = iChineseYear;
		iNextMonth = iChineseMonth;
		bNextLeap = false;
		if ( !bLeap && leap_month == iChineseMonth ) {
			bNextLeap = true;
		}
		else {
			++ iNextMonth;
			if ( iNextMonth == 13 ) {
				iNextMonth = 1;
				++ iNextMonthYear;
			}
		}
	}
};

//1901-2100
inline void GregorianToChinese(const SolarTime& date, LunarTime& lun, int32_t& iBaseDays) noexcept
{
	assert( date.IsValid() && date.Year() >= CalendarConversion::c_base_year && date.Year() <= CalendarConversion::c_max_year );
	//days
	iBaseDays = SolarTimeHelper::CalcDayDelta(CalendarConversion::c_base_year, 1, 1, date.Year(), date.Month(), date.Day());
	int32_t iChineseDay = CalendarConversion::c_base_chinese_day + iBaseDays;
	//hour
	int32_t iDays = date.Hour() + 1;
	if ( iDays == 24 ) {
		iDays = 0;
		++ iChineseDay;
		++ iBaseDays;
	}
	lun.Hour() = iDays / 2 + 1;
	//loop
	int32_t iNextMonthYear, iNextMonth;
	bool bLeap = false, bNextLeap;
	lun.Year() = CalendarConversion::c_base_chinese_year;
	lun.Month() = CalendarConversion::c_base_chinese_month;
	do {
		CalendarConversion::GetChineseMonthInfo(lun.Year(), lun.Month(), bLeap,
					iDays, iNextMonthYear, iNextMonth, bNextLeap);
		if ( iChineseDay <= iDays )
			break;
		lun.Year() = iNextMonthYear;
		lun.Month() = iNextMonth;
      		bLeap = bNextLeap;
		iChineseDay -= iDays;
	} while ( true );
	lun.Day() = iChineseDay;
	//month flags
	lun.SetBig(iDays == 30);
	lun.SetLeap(bLeap);
}

//MonthSolarTerms

struct MonthSolarTerms
{
	int32_t iPrincipleDay;
	int32_t iSectionalDay;
	int32_t iPrincipleTerm;  //1-24
	int32_t iSectionalTerm;  //1-24
};

/*
month      1  2  3  4  5   6   7   8   9  10  11  12
principle 24  2  4  6  8  10  12  14  16  18  20  22
sectional 23  1  3  5  7   9  11  13  15  17  19  21
1 LI CHUN   2 YU SHUI    3 JING ZHE    4 CHUN FEN   5 QING MING  6 GU YU
7 LI XIA    8 XIAO MAN   9 MANG ZHONG  10 XIA ZHI   11 XIAO SHU  12 DA SHU
13 LI QIU   14 CHU SHU   15 BAI LU     16 QIU FEN   17 HAN LU    18 SHUANG JIANG
19 LI DONG  20 XIAO XUE  21 DA XUE     22 DONG ZHI  23 XIAO HAN  24 DA HAN
*/

inline void CalcGregorianMonthSolarTerms(int32_t iYear, int32_t iMonth, MonthSolarTerms& mst) noexcept
{
	assert( iYear >= CalendarConversion::c_base_year && iYear <= CalendarConversion::c_max_year );
//sectional
constexpr const uint8_t c_sectional_term_map[][] = {
{7,6,6,6,6,6,6,6,6,5,6,6,6,5,5,6,6,5,5,5,5,5,5,5,5,4,5,5},
{5,4,5,5,5,4,4,5,5,4,4,4,4,4,4,4,4,3,4,4,4,3,3,4,4,3,3,3},
{6,6,6,7,6,6,6,6,5,6,6,6,5,5,6,6,5,5,5,6,5,5,5,5,4,5,5,5,5},
{5,5,6,6,5,5,5,6,5,5,5,5,4,5,5,5,4,4,5,5,4,4,4,5,4,4,4,4,5},
{6,6,6,7,6,6,6,6,5,6,6,6,5,5,6,6,5,5,5,6,5,5,5,5,4,5,5,5,5},
{6,6,7,7,6,6,6,7,6,6,6,6,5,6,6,6,5,5,6,6,5,5,5,6,5,5,5,5,4,5,5,5,5},
{7,8,8,8,7,7,8,8,7,7,7,8,7,7,7,7,6,7,7,7,6,6,7,7,6,6,6,7,7},
{8,8,8,9,8,8,8,8,7,8,8,8,7,7,8,8,7,7,7,8,7,7,7,7,6,7,7,7,6,6,7,7,7},
{8,8,8,9,8,8,8,8,7,8,8,8,7,7,8,8,7,7,7,8,7,7,7,7,6,7,7,7,7},
{9,9,9,9,8,9,9,9,8,8,9,9,8,8,8,9,8,8,8,8,7,8,8,8,7,7,8,8,8},
{8,8,8,8,7,8,8,8,7,7,8,8,7,7,7,8,7,7,7,7,6,7,7,7,6,6,7,7,7},
{7,8,8,8,7,7,8,8,7,7,7,8,7,7,7,7,6,7,7,7,6,6,7,7,6,6,6,7,7}
};
constexpr const uint8_t c_sectional_term_year[][] = {
{13,49,85,117,149,185,201,250,250},
{13,45,81,117,149,185,201,250,250},
{13,48,84,112,148,184,200,201,250},
{13,45,76,108,140,172,200,201,250},
{13,44,72,104,132,168,200,201,250},
{5 ,33,68,96 ,124,152,188,200,201},
{29,57,85,120,148,176,200,201,250},
{13,48,76,104,132,168,196,200,201},
{25,60,88,120,148,184,200,201,250},
{16,44,76,108,144,172,200,201,250},
{28,60,92,124,160,192,200,201,250},
{17,53,85,124,156,188,200,201,250}
};
	int32_t index = 0;
	int32_t ry = iYear - CalendarConversion::c_base_year + 1;
	while ( ry >= c_sectional_term_year[iMonth - 1][index] )
		index ++;
	mst.iSectionalDay = c_sectional_term_map[iMonth - 1][4 * index + ry % 4];
	mst.iSectionalTerm = ((iMonth - 1) * 2 + 1 + 22) % 24;
constexpr const uint8_t c_principle_term_map[][] = {
{21,21,21,21,21,20,21,21,21,20,20,21,21,20,20,20,20,20,20,20,20,19,
	20,20,20,19,19,20},
{20,19,19,20,20,19,19,19,19,19,19,19,19,18,19,19,19,18,18,19,19,18,
	18,18,18,18,18,18},
{21,21,21,22,21,21,21,21,20,21,21,21,20,20,21,21,20,20,20,21,20,20,
	20,20,19,20,20,20,20},
{20,21,21,21,20,20,21,21,20,20,20,21,20,20,20,20,19,20,20,20,19,19,
	20,20,19,19,19,20,20},
{21,22,22,22,21,21,22,22,21,21,21,22,21,21,21,21,20,21,21,21,20,20,
	21,21,20,20,20,21,21},
{22,22,22,22,21,22,22,22,21,21,22,22,21,21,21,22,21,21,21,21,20,21,
	21,21,20,20,21,21,21},
{23,23,24,24,23,23,23,24,23,23,23,23,22,23,23,23,22,22,23,23,22,22,
	22,23,22,22,22,22,23},
{23,24,24,24,23,23,24,24,23,23,23,24,23,23,23,23,22,23,23,23,22,22,
	23,23,22,22,22,23,23},
{23,24,24,24,23,23,24,24,23,23,23,24,23,23,23,23,22,23,23,23,22,22,
	23,23,22,22,22,23,23},
{24,24,24,24,23,24,24,24,23,23,24,24,23,23,23,24,23,23,23,23,22,23,
	23,23,22,22,23,23,23},
{23,23,23,23,22,23,23,23,22,22,23,23,22,22,22,23,22,22,22,22,21,22,
	22,22,21,21,22,22,22},
{22,22,23,23,22,22,22,23,22,22,22,22,21,22,22,22,21,21,22,22,21,21,
	21,22,21,21,21,21,22}
};
constexpr const uint8_t c_principle_term_year[][] = {
{13,45,81,113,149,185,201},
{21,57,93,125,161,193,201},
{21,56,88,120,152,188,200,201},
{21,49,81,116,144,176,200,201},
{17,49,77,112,140,168,200,201},
{28,60,88,116,148,180,200,201},
{25,53,84,112,144,172,200,201},
{29,57,89,120,148,180,200,201},
{17,45,73,108,140,168,200,201},
{28,60,92,124,160,192,200,201},
{16,44,80,112,148,180,200,201},
{17,53,88,120,156,188,200,201}
};
	index = 0;
	while ( ry >= c_principle_term_year[iMonth - 1][index] )
		index ++;
	mst.iPrincipleDay = c_principle_term_map[iMonth - 1][4 * index + ry % 4];
	mst.iPrincipleTerm = mst.iSectionalTerm + 1;
}

//GanZhi

struct GanZhi
{
	//stem: 1-10, branch: 1-12
	//JIA YI   BIN DING WU   JI GENG XIN REN  GUI
	//ZI  CHOU YIN MAO  CHEN SI WU   WEI SHEN YOU XU HAI
	uint8_t v[8];
};

//beginning: year -722 month 2 GZ: 6-6

inline void CalcGanZhi(const LunarTime& lun, int32_t iBaseDays, GanZhi& gz) noexcept
{
	//year (tail digit):
	// 4 5 6 7 8 9 10 1 2 3
	// 4 5 6 7 8 9 10 1 2 3 4 5
	int32_t t = lun.Year();
	gz.v[0] = (((t % 10) + 6) % 10) + 1;
	gz.v[1] = (((t % 12) + 8) % 12) + 1;
	//month
	t = lun.Month();
	//1--3, 1--3
	gz.v[3] = (t - 1) + 2 + 1;
	gz.v[2] = (((((gz.v[0] - 1) * 12 + t - 1) % 10) + 2) % 10) + 1;
	//day
	t = iBaseDays;
	gz.v[4] = ((t % 10) + 5) % 10 + 1;
	gz.v[5] = ((t % 12) + 3) % 12 + 1;
	//hour
	t = lun.Hour();
	gz.v[7] = t;
	gz.v[6] = (((((gz.v[4] - 1) * 12 + t - 1) % 10) + 0) % 10) + 1;
}

//------------------------------------------------------------------------------

/*
BaZi:
year --- separated by LI CHUN
month --- separated by principle term
*/

////////////////////////////////////////////////////////////////////////////////
}
////////////////////////////////////////////////////////////////////////////////
#endif
////////////////////////////////////////////////////////////////////////////////
